﻿using AppSocketModel;
using System;
using System.Collections.Generic;
using System.Text;
using BCGPSCommon;
using LJD.IMS.Utility;
using AppSocketService.Vehicle;
using BCGPSMongoData; 
using AppSocketService.Location;
using MongoDB.Driver;
using Newtonsoft.Json;
using AppSocketService.SmsService;

namespace AppSocketService.Account
{
    public  class AccountPersonService : ServiceBase, IAccountPersonService
    {
        private readonly MongoDBCommand<AccountDto> mongoDBCommand = new MongoDBCommand<AccountDto>("AccountPerson");
        private readonly MongoDBCommand<VehicleDto> mongoDBCommandVehicle = new MongoDBCommand<VehicleDto>("AccountVehicle");
        private readonly MongoDBCommand<LocationDto> mongoDBCommandLocation = new MongoDBCommand<LocationDto>("AccountVehicleLocation");
        private readonly IRedisService redisService;
        private readonly IAliyunSmsService aliyunSmsService;


        public AccountPersonService(IClaimsAccessor claimsAccesso, IRedisService redisService, IAliyunSmsService aliyunSmsService) : base(claimsAccesso)
        {
            this.redisService = redisService;
            this.aliyunSmsService = aliyunSmsService;
        }

        public AccountPersonService(IRedisService redisService)
        {
            this.redisService = redisService; 
        } 

        #region 初始化REDIS用, 获取全部个人账户
        public List<AccountDto> InitRedisGetAll()
        {
            return mongoDBCommand.SelectDocumentsAsync(s => s.CompanyId ==0).GetAwaiter().GetResult();
        }
        #endregion

        #region 登录
        public AccountDto Login(AccountLoginDto loginDto, string ip)
        { 
            if (loginDto.AccountCodeType == AccountCodeType.ACCOUNT)
            {
                return LoginByAccountCodePwd(loginDto, ip);
            }
            else if (loginDto.AccountCodeType == AccountCodeType.PHONE)
            {
                return LoginByPhoneVerifyCode(loginDto, ip);
            }
            throw new ArgumentException("不支持这种登录方式!");
        }
        private AccountDto LoginByAccountCodePwd(AccountLoginDto loginDto, string ip)
        {
            AccountDto dto = mongoDBCommand.SelectDocumentAsync(s => s.AccountCode == loginDto.AccountCode && s.AccountRole == AccountRole.PERSON).GetAwaiter().GetResult();
            if (dto == null)
                throw new ArgumentException("登录账户不存在");
            if (loginDto.Password.SHA256(loginDto.AccountCode) != dto.Password)
                throw new ArgumentException("账户密码不正确!");

            var update = GetUpdateDefinition(dto, ip);
            var accountDto = mongoDBCommand.UpdateDocumentAsync(s => s.Id == dto.AccountId, update).GetAwaiter().GetResult();
            return accountDto;
        }
        private AccountDto LoginByPhoneVerifyCode(AccountLoginDto loginDto, string ip)
        { 
            AccountDto dto = mongoDBCommand.SelectDocumentAsync(s => s.Phone == loginDto.Phone).GetAwaiter().GetResult();
            if (dto == null)
                throw new ArgumentException("登录账户不存在");


            if (aliyunSmsService.ValidatePassCode(loginDto.Phone, loginDto.VerifyCode))
            {
                var update = GetUpdateDefinition(dto, ip);
                return mongoDBCommand.UpdateDocumentAsync(s => s.Id == dto.AccountId, update).GetAwaiter().GetResult();
            }
            else
            {
                throw new ArgumentException("验证码不正确,登录失败");
            }
        }
        
        private UpdateDefinition<AccountDto> GetUpdateDefinition(AccountDto dto, string ip)
        { 
            return Builders<AccountDto>.Update
                .Set(s => s.LastLoginTime, DateTime.SpecifyKind(DateTime.Now, DateTimeKind.Utc))
                .Set(s => s.LoginTimes, dto.LoginTimes + 1)
                .Set(s => s.LoginIp, ip);
        }
        #endregion

        #region 个人账户号注册
        public AccountDto RegisterPersonAccount(AccountPersonRegisterDto dto)
        {
            if (dto.IMEI.Trim().Length < 13)
                throw new ArgumentException("请输入正确的IMEI号!"); 

            if(!StringHelper.IsMobilePhone(dto.AccountCode))
                    throw new ArgumentException("请输入正确的手机号!");

            var accountDto = mongoDBCommand.SelectDocumentAsync(s => s.AccountCode == dto.AccountCode ).GetAwaiter().GetResult();

            if (accountDto != null)
                throw new ArgumentException("账户号已经被注册!");
              

            if (string.IsNullOrWhiteSpace(dto.Password))
                throw new ArgumentException("请输入密码!");

            if (dto.Password.Trim().Length < 6)
                throw new ArgumentException("密码长度不能小于6个字符!");

            accountDto = dto.As<AccountDto>();
            accountDto.CompanyId = 0;
            accountDto.AccountCodeType = AccountCodeType.PHONE;
            accountDto.AccountRole = AccountRole.PERSON;
            accountDto.Phone = accountDto.AccountCode;
            accountDto.Password = accountDto.Password.SHA256(accountDto.AccountCode);
            accountDto.CreateTime = DateTime.SpecifyKind(DateTime.Now, DateTimeKind.Utc);
             
            mongoDBCommand.InsertDocumentAsync(accountDto);

            var account = mongoDBCommand.SelectDocumentAsync(s => s.AccountCode == accountDto.AccountCode).GetAwaiter().GetResult();

            AddVehecleLocation(account, dto.VehicleNo, dto.IMEI);

            accountDto.Password = null;
            return accountDto;
        }
        private void AddVehecleLocation(AccountDto account,string vehicleNo,string imei)
        {

            VehicleDto vehicleDto = new VehicleDto();
            vehicleDto.IMEI = imei;
            vehicleDto.VehicleNo = vehicleNo;

            vehicleDto.CompanyId = 0;
            vehicleDto.AccountId = account.AccountId;
            vehicleDto.DriverPhone = account.Phone;

            vehicleDto = AddNewPerson(vehicleDto);


            LocationDto locationDto = new LocationDto();
            locationDto.CompanyId = 0;
            locationDto.AccountId = account.AccountId;
            locationDto.IMEI = vehicleDto.IMEI;
            locationDto.VehicleNo = vehicleDto.VehicleNo;
            AddNewPerson(locationDto);

            redisService.AddHashAsync(GeneralContainer.RedisNameSpaceAccountVehiclePerson + account.AccountCode, vehicleDto.IMEI, vehicleDto).GetAwaiter().GetResult();
            redisService.AddAsync(GeneralContainer.RedisNameSpaceIMEILocation + locationDto.IMEI, locationDto);

        }

        private VehicleDto AddNewPerson(VehicleDto vehicleDto)
        { 
            vehicleDto.CreateTime = MongoDBDateTime.GetNowUtc();
            vehicleDto.ModifyTime = MongoDBDateTime.GetNowUtc();
            mongoDBCommandVehicle.InsertDocumentAsync(vehicleDto).GetAwaiter().GetResult();
            return vehicleDto;
        }

        private LocationDto AddNewPerson(LocationDto locationDto)
        {
            mongoDBCommandLocation.InsertDocumentAsync(locationDto).GetAwaiter().GetResult();
            return locationDto;
        }
        #endregion

        #region 个人账户注销
        private bool UnRegisterPersonAccount(AccountPersonUnRegisterDto dto)
        {
            //根据账户号和密码完整删除用户,车辆,位置 
            if (!string.IsNullOrWhiteSpace(dto.AccountCode) && !string.IsNullOrWhiteSpace(dto.Password))
            {
                var accountDto = mongoDBCommand.SelectDocumentAsync(s => s.CompanyId == 0 && s.AccountCode == dto.AccountCode).GetAwaiter().GetResult();
                if (accountDto == null)
                    throw new ArgumentException("账户号不存在!");

                if (dto.Password.SHA256(dto.AccountCode) != accountDto.Password)
                    throw new ArgumentException("账户密码不正确!");

                
                DeleteVehicleAll(accountDto);
                DeleteLocationAll(accountDto);


                var accountDel = mongoDBCommand.DeleteDocumentAsync(s =>s.CompanyId ==  0 &&  s.AccountId == accountDto.AccountId ).GetAwaiter().GetResult().DeletedCount;
                if (accountDel > 0)
                    return true;
                else
                    throw new Exception("删除失败,请重试,或联系客服!");
            }
            throw new ArgumentException("请输入正确的账户号和密码!");
        }


        public bool UnRegisterPersonAccount()
        {
            AccountDto accountDto = GetCurrentAccount();
            if (accountDto == null)
                throw new Exception("登录账户异常,请重新登录 !!!");

            if (accountDto.CompanyId>0)
                throw new Exception("删除失败,账户没有权限注销!");

            DeleteVehicleAll(accountDto);
            DeleteLocationAll(accountDto);

            redisService.DeleteAsync(GeneralContainer.RedisNameSpaceAccount + accountDto.AccountId).GetAwaiter().GetResult();
            var accountDel = mongoDBCommand.DeleteDocumentAsync(s => s.CompanyId == 0 && s.Id == accountDto.Id).GetAwaiter().GetResult().DeletedCount;
            if (accountDel > 0)
                return true;
            else
                throw new Exception("删除失败,请重试,或联系客服!");

        }
        #region 删除设备
        private void DeleteVehicleAll(AccountDto accountDto )
        {
            if (accountDto.CompanyId == 0)
            {
                mongoDBCommandVehicle.DeleteDocumentsAsync(s => s.CompanyId == 0 && s.AccountId == accountDto.AccountId).GetAwaiter().GetResult(); 
            }
            else
                throw new ArgumentException("用户没有权限!");
        }

        private void Delete(string imei,AccountDto accountDto )
        {
            if (accountDto.CompanyId > 0)
            {
                mongoDBCommandVehicle.DeleteDocumentAsync(s => s.CompanyId == s.CompanyId && s.IMEI == imei).GetAwaiter().GetResult();
                redisService.DeleteAsync(GeneralContainer.RedisNameSpaceIMEIAlarm + imei).GetAwaiter().GetResult();
            }
            else
            {
                mongoDBCommandVehicle.DeleteDocumentAsync(s => s.CompanyId == s.CompanyId && s.IMEI == imei && s.AccountId == accountDto.AccountId).GetAwaiter().GetResult();
                redisService.DeleteAsync(GeneralContainer.RedisNameSpaceIMEIAlarm + imei).GetAwaiter().GetResult();
            }
        }

        #endregion

        #region 删除位置
        private void DeleteLocationAll(AccountDto accountDto)
        {
            if (accountDto.CompanyId == 0)
            { 
                mongoDBCommandLocation.DeleteDocumentsAsync(s => s.CompanyId == 0 && s.AccountId == accountDto.AccountId).GetAwaiter().GetResult();
            }
            else
                throw new ArgumentException("用户没有权限!");
        }
        #endregion
        #endregion

        #region 获取当前登录账户
        public AccountDto GetCurrentAccount()
        {
            return mongoDBCommand.SelectDocumentAsync(s => s.Id == claimsAccessor.AccountId).GetAwaiter().GetResult();
        }
        #endregion
        
        #region 修改账户密码 
        public void UpdatePassword(string accountId, string password)
        {
            if (password.Trim().Length < 6)
                throw new ArgumentException("密码不能小于6个字符!");

            var dto = mongoDBCommand.SelectDocumentAsync(s => s.Id == accountId).GetAwaiter().GetResult();
            if (dto == null)
                throw new ArgumentException("该用户不存在!");

            dto.Password = dto.Password.SHA256(dto.AccountCode);
            var update = Builders<AccountDto>.Update
                .Set(s => s.Password, dto.Password);
            mongoDBCommand.UpdateDocumentAsync(s => s.Id == accountId, update).GetAwaiter().GetResult();
        }

        public void ModifyPassword(ModifyPasswordRequestDto requestDto)
        { 
            if (requestDto.NewPassword == null ||  requestDto.NewPassword.Trim().Length < 6)
                throw new ArgumentException("密码不能小于6个字符!");

            AccountDto accountDto = GetCurrentAccount();
            if (requestDto.OldPassword.SHA256(accountDto.AccountCode) != accountDto.Password)
                throw new ArgumentException("原密码不正确!");

            string Password = requestDto.NewPassword.SHA256(accountDto.AccountCode);
            var update = Builders<AccountDto>.Update
                .Set(s => s.Password, Password);
            mongoDBCommand.UpdateDocumentAsync(s => s.Id == accountDto.Id, update).GetAwaiter().GetResult();
        }
        #endregion

        public void SetNewPasswrod(SetPasswordRequestDto requestDto)
        {
            if (requestDto.NewPassword == null || requestDto.NewPassword.Trim().Length < 6)
                throw new ArgumentException("密码不能小于6个字符!");

            AccountDto accountDto = mongoDBCommand.SelectDocumentAsync(s => s.Phone == requestDto.Phone).GetAwaiter().GetResult();
            if (accountDto == null)
                throw new ArgumentException("登录账户不存在");

            if (aliyunSmsService.ValidatePassCode(requestDto.Phone, requestDto.VerifyCode))
            { 
                string Password = requestDto.NewPassword.SHA256(accountDto.AccountCode);
                var update = Builders<AccountDto>.Update
                    .Set(s => s.Password, Password);
                mongoDBCommand.UpdateDocumentAsync(s => s.Id == accountDto.Id, update).GetAwaiter().GetResult();
            }
            else
            {
                throw new ArgumentException("验证码不正确!");
            }
        }
         
        public void SystemAdminSetNewPassword(string phone,string passwrod)
        {
            AccountDto accountDto = mongoDBCommand.SelectDocumentAsync(s => s.Phone == phone).GetAwaiter().GetResult();
            if (accountDto == null)
                throw new ArgumentException("账户不存在");

            string Password = passwrod.SHA256(accountDto.AccountCode);
            var update = Builders<AccountDto>.Update
                .Set(s => s.Password, Password);
            mongoDBCommand.UpdateDocumentAsync(s => s.Id == accountDto.Id, update).GetAwaiter().GetResult();
        }

        #region 获取指定账户下的车辆总数
        private int GetVehicleCount(string accountId)
        {
            int a = mongoDBCommandVehicle.SelectDocumentsAsync(s => s.AccountId == accountId).GetAwaiter().GetResult().Count;
            return a;
        }
        #endregion

        #region SYSTEM 获取全部账户
        public PageableList<AccountDto> SystemGetAll(string accountCode, AccountRole? accountRole, AccountCodeType? accountCodeType, bool desc, int index, int size)
        {
            index = index > 0 ? index - 1 : 0;

            List<string> wheres = new List<string>();
             

            if (accountCodeType.HasValue)
                wheres.Add($"AccountCodeType:{(int)accountCodeType}");

            if (!string.IsNullOrWhiteSpace(accountCode))
                wheres.Add($"AccountCode:/{accountCode}/");

            if (accountRole.HasValue)
                wheres.Add($"AccountRole:{(int)accountRole.Value}");

            string str = "{" + string.Join(" , ", wheres) + "}";

            var list = mongoDBCommand.SelectDocumentsAsync(str, s => s.CreateTime, desc, index * size, size).GetAwaiter().GetResult();


            foreach (var item in list.Items)
            {
                item.SubAccountCount = 0;
                item.VehicleCount = GetVehicleCount(item.Id); 
                item.VehicleTotal = item.VehicleCount; 
            }
            return list;
        }
        #endregion

        #region 通过账号获取账户信息

        public AccountDto GetAccountByCode (string accountCode)
        {
            return mongoDBCommand.SelectDocumentAsync(s => s.AccountCode == accountCode).GetAwaiter().GetResult();
        }
        #endregion
    }
}
